<!-- Copyright Eric Bidelman <ebidel@gmail.com> -->

<link rel="import" href="../polymer/polymer.html">

<!--
Provides the current location using the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/Using_geolocation).

<b>Example - basic</b>

    <geo-location></geo-location>

    <script>
      var loc = document.querySelector('geo-location');
      loc.addEventListener('geo-response', function(e) {
        console.log('lat:' + this.latitude,
                    'lng:' + this.longitude);
      });
    </script>

<b>Example</b> - continuous updates from the device using high accuracy.

    <geo-location watchpos highaccuracy></geo-location>

<b>Example</b> - centering a [Google Map](https://github.com/GoogleWebComponents/google-map) to the current location, using data-binding inside another Polymer element

     <geo-location latitude="{{lat}}"
                   longitude="{{lng}}"></geo-location>
     <google-map latitude="{{lat}}" longitude="{{lng}}"
                 showcentermarker></google-map>

@element geo-location
@blurb Provides the current location using the Geolocation API.
@status stable
@snap https://raw.githubusercontent.com/ebidel/geo-location/master/snap.png
@homepage http://ebidel.github.io/geo-location
-->
<!-- TODO: decide if we need to cache results across instances. -->
<polymer-element name="geo-location" attributes="watchPos highAccuracy position">
  <template>
    <style>
      :host {
        display: none;
      }
    </style>
  </template>
  <script>
    (function() {
      var id_ = null;

      /**
       * Fired when the Geolocation API returns an error.
       *
       * @event geo-error
       * @param {Object} detail
       * @param {boolean} detail.error The error message.
       */
       /**
        * Fired when the Geolocation API returns a position result.
        *
        * @event geo-response
        * @param {Object} detail
        *   @param {Position} position The raw position object returned by the Geolocation API.
        *   @param {Number} detail.latitude Latitude of the current position.
        *   @param {Number} detail.longitude Longitude of the current position.
        */

      Polymer('geo-location', {

        publish: {
          /**
           * The latitude of the current position.
           * 
           * @attribute latitude
           * @type Number
           * @default null
           */
          latitude: {value: null, reflect: true},

          /**
           * The longitude of the current position.
           * 
           * @attribute longitude
           * @type Number
           * @default null
           */
          longitude: {value: null, reflect: true}
        },

        /**
         * If true, the latitude/longitude update as the device changes position.
         * If not set, the latitude/longitude are provided once.
         * 
         * @attribute watchPos
         * @type boolean
         * @default false
         */
        watchPos: false,

        /**
         * If true, enables high accuracy GPS.
         * 
         * @attribute highAccuracy
         * @type boolean
         * @default false
         */
        highAccuracy: false,

        /**
         * The maximumAge option in the Gelocation API.
         * 
         * @property maximumAge
         * @type Number
         * @default 0
         */
        maximumAge: 0,

        /**
         * The timeout option in the Gelocation API.
         * 
         * @property timeout
         * @type Number
         * @default 5000
         */
        timeout: 5000,

        ready: function() {
          var options = {
            enableHighAccuracy: this.highAccuracy,
            timeout: this.timeout,
            maximumAge: this.maximumAge
          };

          if (!this.watchPos) {
            navigator.geolocation.getCurrentPosition(
              this.onPosition.bind(this), this.onError.bind(this), options);
          }
        },
        watchPosChanged: function() {
          if (id_) {
            navigator.geolocation.clearWatch(id_);
            id_ = null;
          }

          if (this.watchPos) {
            var options = {
              enableHighAccuracy: this.highAccuracy,
              timeout: this.timeout,
              maximumAge: this.maximumAge
            };
            id_ = navigator.geolocation.watchPosition(
              this.onPosition.bind(this), this.onError.bind(this), options);
          }
        },
        /**
         * Success callback when the Geolocation API returns results.
         * 
         * @method onPosition
         * @param {Position} pos A position object from the Geolocation API.
         */
        onPosition: function(pos) {
          this.position = pos;
          this.latitude = pos.coords.latitude;
          this.longitude = pos.coords.longitude;
          this.fire('geo-response', {
            latitude: this.latitude,
            longitude: this.longitude,
            position: pos
          });
        },
        /**
         * Error callback when the Geolocation API returns an error.
         * 
         * @method onError
         * @param {Position} err The error that was returned.
         */
        onError: function(err) {
          this.fire('geo-error', {
            error: err.code + ': ' + err.message
          });
        }
      });
    })();
  </script>
</polymer-element>
